package com.randi.framework.domain.service.impl;

import com.randi.common.constant.Constants;
import com.randi.common.core.domain.vo.SaltInfo;
import com.randi.framework.domain.dto.UserLoginDTO;
import com.randi.common.core.domain.model.LoginUser;
import com.randi.common.enums.ResultCode;
import com.randi.common.exception.ServiceException;
import com.randi.common.utils.SecurityUtils;
import com.randi.common.utils.StringUtils;
import com.randi.common.utils.secret.SecretUtils;
import com.randi.framework.security.context.AuthenticationContextHolder;
import com.randi.framework.domain.service.ISysLoginService;
import com.randi.framework.domain.service.ISysTokenService;
import com.randi.system.service.ISysSaltService;
import com.randi.system.service.SysLogThreadService;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author ziye
 */
@Service
public class SysLoginServiceImpl implements ISysLoginService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private ISysTokenService iSysTokenService;

    @Resource
    private ISysSaltService iSysSaltService;

    @Resource
    private SysLogThreadService sysLogThreadService;

    /**
     * 密码解密处理
     *
     * @param userLoginDto loginBody
     */
    private void handleDecryptPassword(UserLoginDTO userLoginDto) {
        if (StringUtils.isEmpty(userLoginDto.getUuid())) {
            return;
        }

        SaltInfo saltInfo = iSysSaltService.getSaltInfo(userLoginDto.getUuid());
        if (saltInfo == null || StringUtils.isEmpty(saltInfo.getSalt())) {
            throw new ServiceException(ResultCode.SECRET_SALT_EXPIRE);
        }
        // 密码解密
        String password = SecretUtils.decrypt(userLoginDto.getPassword(), saltInfo.getSalt());
        userLoginDto.setPassword(password);

        // 清除加密盐缓存
        iSysSaltService.removeSaltInfo(userLoginDto.getUuid());
    }

    /**
     * 用户登录
     *
     * @param userLoginDTO loginBody
     * @return token
     */
    @Override
    public HashMap<String, String> loginByPassword(UserLoginDTO userLoginDTO) {
        this.handleDecryptPassword(userLoginDTO);
        String username = userLoginDTO.getUserName();
        String password = userLoginDTO.getPassword();

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        AuthenticationContextHolder.setContext(authenticationToken);
        // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        AuthenticationContextHolder.clearContext();

        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        return iSysTokenService.buildToken(loginUser);
    }

    /**
     * 登录续期
     *
     * @param request request
     * @return token
     */
    @Override
    public HashMap<String, String> refreshToken(HttpServletRequest request) {
        return iSysTokenService.refreshToken(request);
    }

    /**
     * 退出登录
     */
    @Override
    public void logout() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        iSysTokenService.removeTokenCache(loginUser.getUuid());
        sysLogThreadService.handleLoginInfo(loginUser.getUserName(), Constants.LOGIN_OUT, ResultCode.LOGIN_OUT_SUCCESS.message());
    }

}
